package com.huan.es8.aggregations.bucket;

import co.elastic.clients.elasticsearch._types.aggregations.CalendarInterval;
import co.elastic.clients.elasticsearch._types.aggregations.FieldDateMath;
import co.elastic.clients.elasticsearch._types.mapping.DateProperty;
import co.elastic.clients.elasticsearch._types.mapping.KeywordProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import co.elastic.clients.util.DateTime;
import com.huan.es8.AbstractEs8Api;
import org.junit.jupiter.api.*;

import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;

/**
 * 直方图聚合
 *
 * @author huan.fu
 * @date 2022/11/23 - 22:22
 * @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-datehistogram-aggregation.html#date-histogram-missing-value">官方文档</a>
 * @see <a href="https://blog.csdn.net/fu_huo_1993/article/details/128093563">博客地址</a>
 */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class DateHistogramAggs extends AbstractEs8Api {

    @BeforeAll
    public void createIndex() throws IOException {
        client.indices()
                .create(indexRequest ->
                        indexRequest.index("index_api_invoked_time")
                                .mappings(mappings ->
                                        mappings.properties("id", new Property(new KeywordProperty.Builder().build()))
                                                .properties("api", new Property(new KeywordProperty.Builder().build()))
                                                .properties("invoked_time", new Property(new DateProperty.Builder().format("yyyy-MM-dd HH:mm:ss").build()))
                                )
                );
        bulk("index_api_invoked_time", Arrays.asList(
                "{\"api\":\"/user/infos\",\"invoked_time\": \"2022-11-26 00:00:00\"}",
                "{\"api\":\"/user/add\"}",
                "{\"api\":\"/user/update\",\"invoked_time\": \"2022-11-26 23:59:59\"}",
                "{\"api\":\"/user/list\",\"invoked_time\": \"2022-11-27 00:00:00\"}",
                "{\"api\":\"/user/export\",\"invoked_time\": \"2022-11-29 23:59:59\"}",
                "{\"api\":\"/user/detail\",\"invoked_time\": \"2022-12-01 01:00:00\"}"
        ));
    }

    @Test
    @DisplayName("日期直方图聚合")
    public void test01() throws IOException {
        SearchRequest request = SearchRequest.of(searchRequest ->
                searchRequest.index("index_api_invoked_time")
                        .size(0)
                        .aggregations("agg_01", agg ->
                                agg.dateHistogram(dateAgg ->
                                        // 聚合的字段
                                        dateAgg.field("invoked_time")
                                                // 聚合的单位，日历感知 单位为天，此时的一天不一定为24小时，因为夏令时时，有些国家一天可能只有23个小时
                                                .calendarInterval(CalendarInterval.Day)
                                                // 固定间隔， 此处可以指定 1天就是24小时
                                                // .fixedInterval()
                                                // 如果聚合的桶中，没有文档也返回
                                                .minDocCount(0)
                                                // 对于文档中，聚合字段缺失，此处给一个默认值，默认情况是此文档不参与聚合
                                                .missing(DateTime.of("2022-11-27 23:59:59", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))
                                                // 时区
                                                .timeZone("+08:00")
                                                // 偏移，偏移是在时间在对应的时区调整之后，再去偏移
                                                .offset(time -> time.time("+10h"))
                                                // 如果返回的桶数据不在这个边界中，则给默认值，不会对数据进行过滤。
                                                .extendedBounds(bounds ->
                                                        bounds.min(FieldDateMath.of(f -> f.expr("2022-11-26 10:00:00")))
                                                                .max(FieldDateMath.of(f -> f.expr("2022-12-03 10:00:00")))
                                                )
                                )
                        )
        );
        System.out.println("request: " + request);
        SearchResponse<String> response = client.search(request, String.class);
        System.out.println("response: " + response);
    }

    @AfterAll
    public void deleteIndex() throws IOException {
        deleteIndex("index_api_invoked_time");
    }
}
